Þ ¥bonds€¬cell_resultsÞ 0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Цqueued¤logs�§running¦output†¤bodyÙ¼
That's all you need! Pluto will synchronise the value of x with the latest value of the HTML input. Try moving the slider! 👆
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0_p°persist_js_state·has_pluto_hook_features§cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2¹depends_on_disabled_cells§runtimeÎ ¹µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eЦqueued¤logs�§running¦output†¤bodyÚ
Click me!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0¼4°persist_js_state·has_pluto_hook_features§cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e¹depends_on_disabled_cells§runtimeÎ µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557dbЦqueued¤logs�§running¦output†¤bodyÚßTip
In this example, we immediately call update() and trigger an input event with the initial value. If we didn't do that, the value of counter would be nothing until the first interaction. Whether that's appropriate, depends on the interaction you want. In this case, it made sense that the counter should start at 0!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0ýr°persist_js_state·has_pluto_hook_features§cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db¹depends_on_disabled_cells§runtimeÎ U³µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fЦqueued¤logs�§running¦output†¤bodyÚtThe script is now keeping track of clicks, but it's not sending that value anywhere.
We need to:
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0£¾°persist_js_state·has_pluto_hook_features§cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f¹depends_on_disabled_cells§runtimeÎ ‚5µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$33b5374c-91d1-4122-82c5-f793d063ffdcЦqueued¤logs�§running¦output†¤bodyÙ@ ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3¿
N°persist_js_state·has_pluto_hook_features§cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc¹depends_on_disabled_cells§runtimeÎ Îȵpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$4a235d55-a80f-43c7-8f13-759976d88656Цqueued¤logs�§running¦output†¤bodyÙA ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3¾á°persist_js_state·has_pluto_hook_features§cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656¹depends_on_disabled_cells§runtimeÎ
ɘµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$788c0b9b-238f-4402-b24f-52648103512eЦqueued¤logs�§running¦output†¤bodyÙðIf you're looking for something more sophisticated than simple string interpolation, check out the HyperTextLiteral package !
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0Ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e¹depends_on_disabled_cells§runtimeÎ ÊRµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2969d603-9b6c-403e-abdc-af078c2e53f1Цqueued¤logs�§running¦output†¤bodyÙw
Let's make something interactive here!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0:—°persist_js_state·has_pluto_hook_features§cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1¹depends_on_disabled_cells§runtimeÎ Ñyµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6eЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†3ù6ưpersist_js_state·has_pluto_hook_features§cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e¹depends_on_disabled_cells§runtimeͰµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$73c8532e-09a6-429b-b8f6-530c00d92428Цqueued¤logs�§running¦output†¤bodyÚøInteractivity with HTML
Pluto notebooks can use the @bind macro for interactive inputs. Neat!
If you're completely new to coding anything interactive in a web browser, the easiest way to get started is with the PlutoUI package in Julia. (Check out the PlutoUI featured notebook if you'd like to learn more about that!)
If you have some experience with HTML, or if you would like to learn how to make your own interactive elements, this notebook is for you! We'll cover the basics of using @bind with HTML elements. Let's get started!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0s°persist_js_state·has_pluto_hook_features§cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428¹depends_on_disabled_cells§runtimeÎ Ó5µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$1ebba747-47f8-4ecd-809d-359e6d803ddcЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassignee¡y²last_run_timestampËAÚ†3¾²Ì°persist_js_state·has_pluto_hook_features§cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc¹depends_on_disabled_cells§runtimeÍ/¨µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacЦqueued¤logs�§running¦output†¤bodyÚBehind the scenes
If you're curious to learn a bit more about how this all works, keep reading!
The output value
As we've mentioned, bound values are just the latest value of the input element, rather than some kind of observable.
The update mechanism is lossy and lazy , which means that it will skip values if your code is still running - and only send the latest value when your code is ready again . This is important when changing a slider from 0 to 100, for example. If it would send all intermediate values, it might take a while for your code to process everything, causing a noticeable lag.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0^ê°persist_js_state·has_pluto_hook_features§cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac¹depends_on_disabled_cells§runtimeÎ Âýµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$de1b9643-66fa-4918-9a93-0f340c8548baЦqueued¤logs�§running¦output†¤bodyÙ²Now we can use the script to handle whatever interaction we want. For a simple element, let's add a button and count the number of clicks.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0X*°persist_js_state·has_pluto_hook_features§cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba¹depends_on_disabled_cells§runtimeÎ 6µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$82c7b1ea-08c0-495f-baba-37e5497abde2Цqueued¤logs�§running¦output†¤bodyÙC¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0Ýv°persist_js_state·has_pluto_hook_features§cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2¹depends_on_disabled_cells§runtimeÎ Ärµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cb65a4ee-02e5-4779-8728-b994d8af645dЦqueued¤logs�§running¦output†¤body§Missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†3»Š3°persist_js_state·has_pluto_hook_features§cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d¹depends_on_disabled_cells§runtimeÍ#xµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013Цqueued¤logs�§running¦output†¤bodyÚ
Click me!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3ùŒ¹°persist_js_state·has_pluto_hook_features§cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013¹depends_on_disabled_cells§runtimeÎ 7Àµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dЦqueued¤logs�§running¦output†¤bodyÙA ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3¿â†°persist_js_state·has_pluto_hook_features§cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d¹depends_on_disabled_cells§runtimeÎ }„µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ced18648-7eb2-11ea-2052-07795685f0daЦqueued¤logs�§running¦output†¤bodyÚdJavaScript?
Yes! We are using Generator.input from observablehq/stdlib to create a JS Generator (kind of like an Observable) that listens to onchange, onclick or oninput events, depending on the element type .
This makes it super easy to create nice HTML/JS-based interaction elements - a package creator simply has to write a show method for MIME type text/html that creates a DOM object that triggers the input event. In other words, Pluto's @bind will behave exactly like viewof in observablehq .
If you want to learn more about using Javascript in Pluto, check out the JavaScript sample notebook !
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0â‚°persist_js_state·has_pluto_hook_features§cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da¹depends_on_disabled_cells§runtimeÎ ùXµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dЦqueued¤logs�§running¦output†¤bodyÙœKeep in mind that changing the value of limit will re-evaluate the slider cell, so it will reset the value.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0?§°persist_js_state·has_pluto_hook_features§cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d¹depends_on_disabled_cells§runtimeÎ x›µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$bd24d02c-7eac-11ea-14ab-95021678e71eЦqueued¤logs�§running¦output†¤bodyÙ@ ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3JBF°persist_js_state·has_pluto_hook_features§cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e¹depends_on_disabled_cells§runtimeÎ0 âµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$0a7018ca-2afe-42b1-850f-a649e570709fЦqueued¤logs�§running¦output†¤bodyÙ–A neat aspect of this @bind macro is that on the Julia side, x is just a normal integer:
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0€å°persist_js_state·has_pluto_hook_features§cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f¹depends_on_disabled_cells§runtimeÎ %+µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Цqueued¤logs�§running¦output†¤bodyÙõ
You can use binds with anything that fires an input event . For example:
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0Ãç°persist_js_state·has_pluto_hook_features§cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955¹depends_on_disabled_cells§runtimeÎ ›µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aЦqueued¤logs�§running¦output†¤bodyÙ? ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3À€°persist_js_state·has_pluto_hook_features§cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a¹depends_on_disabled_cells§runtimeÎ
½µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Цqueued¤logs�§running¦output†¤bodyÚŒTip
Interpolating values in Javascript is neat, but remember that we are just taking the string representation of the variable and pasting it in the javascript code. For some complex data types like dates, you will need to do a bit of conversion to turn them into proper javascript expressions.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0~¦°persist_js_state·has_pluto_hook_features§cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51¹depends_on_disabled_cells§runtimeÎ âµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdЦqueued¤logs�§running¦output†¤bodyÚÐUsing Julia values in HTML
We've seen how you can pass on values from an interactive HTML element on to Julia, but for proper interaction, we also want to do it the other way around!
The most basic way to do this is string interpolation. In this example, you can change the value of limit in the code to affect the maximum value of the slider. Try it out!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0!ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd¹depends_on_disabled_cells§runtimeΠܵpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Цqueued¤logs�§running¦output†¤bodyÙm ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†4¶°persist_js_state·has_pluto_hook_features§cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122¹depends_on_disabled_cells§runtimeÎ
whµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Цqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†3ís°persist_js_state·has_pluto_hook_features§cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881¹depends_on_disabled_cells§runtimeÍ$µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$e3eb31ae-c512-426f-915c-01144edbc90dЦqueued¤logs�§running¦output†¤bodyÚÔ
Click me!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3ì~9°persist_js_state·has_pluto_hook_features§cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d¹depends_on_disabled_cells§runtimeÎ&¡Ëµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Цqueued¤logs�§running¦output†¤bodyÙÈFor something even fancier, you can also interpolate value in Javascript. For example, here I have adapted my counter so it won't count past limit:
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0\£°persist_js_state·has_pluto_hook_features§cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6¹depends_on_disabled_cells§runtimeÎ
µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$3297233b-9567-4d5e-8138-93ebe20fed48Цqueued¤logs�§running¦output†¤bodyƒ¨elements’’’§missingªtext/plain’’§missingªtext/plain¤type¥Tuple¨objectid°ffffffff944f3bac¤mimeÙ!application/vnd.pluto.tree+object¬rootassigneeÀ²last_run_timestampËAÚ†4Ñ‘°persist_js_state·has_pluto_hook_features§cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48¹depends_on_disabled_cells§runtimeÍ\0µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cb1fd532-7eac-11ea-307c-ab16b1977819Цqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†3v»,°persist_js_state·has_pluto_hook_features§cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819¹depends_on_disabled_cells§runtimeÍHXµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$9985a640-c1d3-48dc-b00b-d7500085a37bЦqueued¤logs�§running¦output†¤bodyÙŠ
First
Second
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3¿‰ã°persist_js_state·has_pluto_hook_features§cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b¹depends_on_disabled_cells§runtimeÎ
ã_µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$816ea402-7eae-11ea-2134-fb595cca3068Цqueued¤logs�§running¦output†¤bodyÚNot an observable, callback, or something else that you need to wrap your head around. You can use x like you would any other number, and Pluto's reactivity means anything depending on x will be updated with it. 🚀
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0ŸQ°persist_js_state·has_pluto_hook_features§cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068¹depends_on_disabled_cells§runtimeÎ Qеpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Цqueued¤logs�§running¦output†¤bodyÙD ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3¿aF°persist_js_state·has_pluto_hook_features§cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¹depends_on_disabled_cells§runtimeÎ '—µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfЦqueued¤logs�§running¦output†¤bodyÙ‚Okay, now we can use this HTML snippet with a @bind macro and see the result!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0Ú°persist_js_state·has_pluto_hook_features§cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf¹depends_on_disabled_cells§runtimeÎ Ùµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Цqueued¤logs�§running¦output†¤bodyÙZ
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†3ø«z°persist_js_state·has_pluto_hook_features§cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761¹depends_on_disabled_cells§runtimeÎ ¯µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c5a5e243-39d6-43d9-8de7-887661ba99cdЦqueued¤logs�§running¦output†¤bodyÙm ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†4۰persist_js_state·has_pluto_hook_features§cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd¹depends_on_disabled_cells§runtimeÎ
ÅØµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bЦqueued¤logs�§running¦output†¤bodyÚfThis is is how the PlutoUI package works - it defines HTML literals - sometimes with their own scripts.
If you've written some cool HTML inputs and you want to share them with others, you can also make a UI package! Just publish those definitions as a Julia package and you're done! ✨
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0(ž°persist_js_state·has_pluto_hook_features§cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b¹depends_on_disabled_cells§runtimeÎ ˆÈµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaЦqueued¤logs�§running¦output†¤bodyÙôReusing elements
Once you've written some neat interactive element, you may want to use it a few times in notebook. The easiest way is to put the HTML literal in a variable.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0¿Y°persist_js_state·has_pluto_hook_features§cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa¹depends_on_disabled_cells§runtimeÎ ¢óµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fЦqueued¤logs�§running¦output†¤bodyÚBWhat does the macro do?
The @bind macro does not actually contain the interactivity mechanism, this is built into Pluto itself. Still, it does two things: it assigns a default value to the variable (missing in most cases), and it wraps the second argument in a PlutoRunner.Bond object.
For example, expanding the @bind macro turns this expression:
@bind x Slider(5:15)
into (simplified):
begin
local el = Slider(5:15)
global x = AbstractPlutoDingetjes.intial_value(el)
PlutoRunner.create_bond(el, :x)
end
We see that the macro creates a variable x, which is given the value AbstractPlutoDingetjes.intial_value(el). This function returns missing by default, unless a method was implemented for your widget type. For example, PlutoUI has a Slider type, and it defines a method for intial_value(slider::Slider) that returns the default number.
Declaring a default value using AbstractPlutoDingetjes is not necessary , as shown by the earlier examples in this notebook, but the default value will be used for x if the notebook.jl file is run as a plain julia file , without Pluto's interactivity.
You don't need to worry about this if you are just getting started with Pluto and interactive elements, but more advanced users should take a look at AbstractPlutoDingetjes.jl .
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0¢Œ°persist_js_state·has_pluto_hook_features§cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f¹depends_on_disabled_cells§runtimeÎ
f
µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfЦqueued¤logs�§running¦output†¤bodyƒ¨elements–’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain¤type¥Tuple¨objectid°ffffffff2bb69edc¤mimeÙ!application/vnd.pluto.tree+object¬rootassigneeÀ²last_run_timestampËAÚ†3ì!�°persist_js_state·has_pluto_hook_features§cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf¹depends_on_disabled_cells§runtimeÍ8µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Цqueued¤logs�§running¦output†¤bodyÚ
You can also use Javascript to write more complicated inputs.
To get started with this, add a <script> tag to your cell. The easiest setup is to make the script a child of the cell's root element. Then you can use currentScript.parentElement to select the script's parent element.
For instance, here a HTML snippet with a script added to it.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0!Ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403¹depends_on_disabled_cells§runtimeÎ �tµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Цqueued¤logs�§running¦output†¤bodyÙì
Click me!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0p °persist_js_state·has_pluto_hook_features§cell_idÙ$f1f53700-099b-4653-93f1-6b39acdc4c58¹depends_on_disabled_cells§runtimeÎ ¢éµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Цqueued¤logs�§running¦output†¤body ¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†4yÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646¹depends_on_disabled_cells§runtimeÎ @•µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$db24490e-7eac-11ea-094e-9d3fc8f22784Цqueued¤logs�§running¦output†¤bodyÚDBound variables
A basic interactive cell looks like this: we use the @bind macro, define a Julia variable, and add a bit of HTML code that creates an <input> element. The HTML element will be rendered as the cell's output.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0@¼°persist_js_state·has_pluto_hook_features§cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784¹depends_on_disabled_cells§runtimeÎ Cµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$901c2b84-14b8-4deb-89d6-705a4972582cЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ†3ú<Ͱpersist_js_state·has_pluto_hook_features§cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c¹depends_on_disabled_cells§runtimeÍJˆµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2714a923-2be5-4cf9-97dd-75347968dfeeЦqueued¤logs�§running¦output†¤body¡5¤mimeªtext/plain¬rootassignee¥limit²last_run_timestampËAÚ†3ð#£°persist_js_state·has_pluto_hook_features§cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee¹depends_on_disabled_cells§runtimeÍ"µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$863c5996-9892-4bfc-96ba-225fa4a2266cЦqueued¤logs�§running¦output†¤bodyÚOTip
To avoid confusing your readers, it's a good idea to put a ; at the end of the cell where you define the interactive element, like we did here. This way, we only show sliders that are actually bound to something.
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ†0þ.°persist_js_state·has_pluto_hook_features§cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c¹depends_on_disabled_cells§runtimeÎ îCµpublished_object_keys�¸depends_on_skipped_cells§errored±cell_dependenciesÞ 0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2„´precedence_heuristic §cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$beb9a2bd-cbf5-4679-8403-fc249191f65e„´precedence_heuristic §cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557db„´precedence_heuristic §cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f„´precedence_heuristic §cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$33b5374c-91d1-4122-82c5-f793d063ffdc„´precedence_heuristic §cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc´downstream_cells_map�¡b‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$4a235d55-a80f-43c7-8f13-759976d88656„´precedence_heuristic §cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656´downstream_cells_map�¡a‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$788c0b9b-238f-4402-b24f-52648103512e„´precedence_heuristic §cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$2969d603-9b6c-403e-abdc-af078c2e53f1„´precedence_heuristic §cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6e„´precedence_heuristic §cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e´downstream_cells_map€²upstream_cells_map�§limited‘Ù$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$73c8532e-09a6-429b-b8f6-530c00d92428„´precedence_heuristic §cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$1ebba747-47f8-4ecd-809d-359e6d803ddc„´precedence_heuristic §cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc´downstream_cells_map�¡y�²upstream_cells_map‚¡^�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac„´precedence_heuristic §cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$de1b9643-66fa-4918-9a93-0f340c8548ba„´precedence_heuristic §cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$82c7b1ea-08c0-495f-baba-37e5497abde2„´precedence_heuristic §cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$cb65a4ee-02e5-4779-8728-b994d8af645d„´precedence_heuristic §cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d´downstream_cells_map€²upstream_cells_map‚¦typeof�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013„´precedence_heuristic §cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013´downstream_cells_map�¯limited_counter‘Ù$901c2b84-14b8-4deb-89d6-705a4972582c²upstream_cells_map‰¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¤HTML�¯Core.applicable�¨Base.get�¥@bind�¥limit‘Ù$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d„´precedence_heuristic §cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d´downstream_cells_map�¡e‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$ced18648-7eb2-11ea-2052-07795685f0da„´precedence_heuristic §cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$e2854aa0-e3c5-423d-80d9-fc875c5dd54d„´precedence_heuristic §cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$bd24d02c-7eac-11ea-14ab-95021678e71e„´precedence_heuristic §cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e´downstream_cells_map�¡x“Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$0a7018ca-2afe-42b1-850f-a649e570709f„´precedence_heuristic §cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$5301eb68-7f14-11ea-3ff6-1f075bf73955„´precedence_heuristic §cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$f595bdb6-bd15-4c62-9de6-49f14c7d365a„´precedence_heuristic §cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a´downstream_cells_map�¡f‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$d5b3adc5-2c99-4901-adf5-8d8579a32b51„´precedence_heuristic §cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$c50a5e52-7c95-445c-86ee-c60104a39dbd„´precedence_heuristic §cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$3b6dc6d5-ce96-40f6-97f7-511ea6d49122„´precedence_heuristic §cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122´downstream_cells_map�¢x2‘Ù$3297233b-9567-4d5e-8138-93ebe20fed48²upstream_cells_mapˆ¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¯Core.applicable�¨myslider‘Ù$2d8661f1-6f78-4161-a306-982e3ddf3646¥@bind�¨Base.get�Ù$5bd8b261-a89d-46a3-bb59-c95a1801c881„´precedence_heuristic §cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881´downstream_cells_map€²upstream_cells_map�§counter‘Ù$e3eb31ae-c512-426f-915c-01144edbc90dÙ$e3eb31ae-c512-426f-915c-01144edbc90d„´precedence_heuristic §cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d´downstream_cells_map�§counter‘Ù$5bd8b261-a89d-46a3-bb59-c95a1801c881²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$2cefd0de-db13-49c1-abeb-097792ef46f6„´precedence_heuristic §cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$3297233b-9567-4d5e-8138-93ebe20fed48„´precedence_heuristic §cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48´downstream_cells_map€²upstream_cells_map‚¢x1‘Ù$c5a5e243-39d6-43d9-8de7-887661ba99cd¢x2‘Ù$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$cb1fd532-7eac-11ea-307c-ab16b1977819„´precedence_heuristic §cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819´downstream_cells_map€²upstream_cells_map�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$9985a640-c1d3-48dc-b00b-d7500085a37b„´precedence_heuristic §cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b´downstream_cells_map�¡d‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$816ea402-7eae-11ea-2134-fb595cca3068„´precedence_heuristic §cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$d38d06f2-90ce-4e5a-9218-f5a52812e4a2„´precedence_heuristic §cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2´downstream_cells_map�¡c‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf„´precedence_heuristic §cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$1a338f77-d8f3-4569-a2d5-c174368a4761„´precedence_heuristic §cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761´downstream_cells_map�§limited‘Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6e²upstream_cells_map‰¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¤HTML�¯Core.applicable�¨Base.get�¥@bind�¥limit‘Ù$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd„´precedence_heuristic §cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd´downstream_cells_map�¢x1‘Ù$3297233b-9567-4d5e-8138-93ebe20fed48²upstream_cells_mapˆ¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¯Core.applicable�¨myslider‘Ù$2d8661f1-6f78-4161-a306-982e3ddf3646¥@bind�¨Base.get�Ù$ff3abf71-cff6-459d-a622-0ec0ca8f164b„´precedence_heuristic §cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$bb4b557b-e4fc-45f3-9d1f-060198167bfa„´precedence_heuristic §cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$8f829274-7eb1-11ea-3888-13c00b3ba70f„´precedence_heuristic §cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf„´precedence_heuristic §cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf´downstream_cells_map€²upstream_cells_map†¡f‘Ù$f595bdb6-bd15-4c62-9de6-49f14c7d365a¡c‘Ù$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¡e‘Ù$b6501bfb-5e1d-40b9-bd16-d38085d2611d¡b‘Ù$33b5374c-91d1-4122-82c5-f793d063ffdc¡a‘Ù$4a235d55-a80f-43c7-8f13-759976d88656¡d‘Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403„´precedence_heuristic §cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$f1f53700-099b-4653-93f1-6b39acdc4c58„´precedence_heuristic §cell_idÙ$f1f53700-099b-4653-93f1-6b39acdc4c58´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$2d8661f1-6f78-4161-a306-982e3ddf3646„´precedence_heuristic §cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646´downstream_cells_map�¨myslider’Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$db24490e-7eac-11ea-094e-9d3fc8f22784„´precedence_heuristic §cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$901c2b84-14b8-4deb-89d6-705a4972582c„´precedence_heuristic §cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c´downstream_cells_map€²upstream_cells_map�¯limited_counter‘Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$2714a923-2be5-4cf9-97dd-75347968dfee„´precedence_heuristic §cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee´downstream_cells_map�¥limit’Ù$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013²upstream_cells_map€Ù$863c5996-9892-4bfc-96ba-225fa4a2266c„´precedence_heuristic §cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�´cell_execution_orderÜ 0Ù$73c8532e-09a6-429b-b8f6-530c00d92428Ù$db24490e-7eac-11ea-094e-9d3fc8f22784Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$0a7018ca-2afe-42b1-850f-a649e570709fÙ$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$816ea402-7eae-11ea-2134-fb595cca3068Ù$1ebba747-47f8-4ecd-809d-359e6d803ddcÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Ù$4a235d55-a80f-43c7-8f13-759976d88656Ù$33b5374c-91d1-4122-82c5-f793d063ffdcÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Ù$2969d603-9b6c-403e-abdc-af078c2e53f1Ù$de1b9643-66fa-4918-9a93-0f340c8548baÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfÙ$e3eb31ae-c512-426f-915c-01144edbc90dÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557dbÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdÙ$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6eÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$901c2b84-14b8-4deb-89d6-705a4972582cÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Ù$788c0b9b-238f-4402-b24f-52648103512eÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$3297233b-9567-4d5e-8138-93ebe20fed48Ù$82c7b1ea-08c0-495f-baba-37e5497abde2Ù$863c5996-9892-4bfc-96ba-225fa4a2266cÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fÙ$ced18648-7eb2-11ea-2052-07795685f0da´last_hot_reload_timeË ©shortpathºInteractivity with HTML.jl®process_status¥ready¤pathÙQ/home/fons/featured-slider-server/featured_fix/src/web/Interactivity with HTML.jlpluto_version¦v1.0.0®last_save_timeËAÚ†0pªcell_orderÜ 0Ù$73c8532e-09a6-429b-b8f6-530c00d92428Ù$db24490e-7eac-11ea-094e-9d3fc8f22784Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$0a7018ca-2afe-42b1-850f-a649e570709fÙ$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$816ea402-7eae-11ea-2134-fb595cca3068Ù$1ebba747-47f8-4ecd-809d-359e6d803ddcÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Ù$4a235d55-a80f-43c7-8f13-759976d88656Ù$33b5374c-91d1-4122-82c5-f793d063ffdcÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Ù$2969d603-9b6c-403e-abdc-af078c2e53f1Ù$de1b9643-66fa-4918-9a93-0f340c8548baÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfÙ$e3eb31ae-c512-426f-915c-01144edbc90dÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557dbÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdÙ$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6eÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$901c2b84-14b8-4deb-89d6-705a4972582cÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Ù$788c0b9b-238f-4402-b24f-52648103512eÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$3297233b-9567-4d5e-8138-93ebe20fed48Ù$82c7b1ea-08c0-495f-baba-37e5497abde2Ù$863c5996-9892-4bfc-96ba-225fa4a2266cÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fÙ$ced18648-7eb2-11ea-2052-07795685f0dajulia_version§v1.12.4±published_objects€¥nbpkgНinstall_time_nsÎ8R}L¬instantiatedòinstalled_versions‚Ù!__internal_julia_manifest_version¦1.12.4¸__internal_julia_version¦1.12.4°terminal_outputs�ªnbpkg_syncÚ
[0m[1mWaiting for the package registry to update...[22m
[90m===[39m
[0m[1mResolving...[22m
[90m===[39m
[36m[1m Project[22m[39m No packages added to or removed from `~/.julia/scratchspaces/c3e4b0f8-55cb-11ea-2926-15256bba5781/pkg_envs/env_bfhpkzpcbx/Project.toml`
[36m[1m Manifest[22m[39m No packages added to or removed from `~/.julia/scratchspaces/c3e4b0f8-55cb-11ea-2926-15256bba5781/pkg_envs/env_bfhpkzpcbx/Manifest.toml`
[0m[1mInstantiating...[22m
[90m===[39m
[0m[1mPrecompiling...[22m
[90m===[39m§enabled÷restart_recommended_msgÀ´restart_required_msgÀbusy_packages�¶waiting_for_permissionÂÙ,waiting_for_permission_but_probably_disabled«cell_inputsÞ 0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2„§cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2¤codeÙ‹md"""
That's all you need! Pluto will synchronise the value of `x` with the latest value of the HTML input. Try moving the slider! 👆
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e„§cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e¤codeÚ«html"""
Click me!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db„§cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db¤codeÚTmd"""
!!! tip
In this example, we immediately call `update()` and trigger an input event with the initial value. If we didn't do that, the value of `counter` would be `nothing` until the first interaction. Whether that's appropriate, depends on the interaction you want. In this case, it made sense that the counter should start at 0!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f„§cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f¤codeÙümd"""
The script is now keeping track of clicks, but it's not sending that value anywhere.
We need to:
- Update the parent's element `value` property (this is what Pluto will be reading).
- Dispatch an `"input"` event to trigger change detection.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$33b5374c-91d1-4122-82c5-f793d063ffdc„§cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc¤codeÙ @bind b html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$4a235d55-a80f-43c7-8f13-759976d88656„§cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656¤codeÙ!@bind a html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$788c0b9b-238f-4402-b24f-52648103512e„§cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e¤codeÙÃmd"""
If you're looking for something more sophisticated than simple string interpolation, check out the [HyperTextLiteral package](https://juliapluto.github.io/HypertextLiteral.jl/stable/)!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$2969d603-9b6c-403e-abdc-af078c2e53f1„§cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1¤codeÙ‚html"""
Let's make something interactive here!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e„§cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e¤code§limited¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$73c8532e-09a6-429b-b8f6-530c00d92428„§cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428¤codeÚ[md"""
# Interactivity with HTML
Pluto notebooks can use the `@bind` macro for interactive inputs. Neat!
If you're completely new to coding anything interactive in a web browser, the easiest way to get started is with the `PlutoUI` package in Julia. (Check out the [PlutoUI featured notebook](https://featured.plutojl.org/basic/plutoui.jl) if you'd like to learn more about that!)
If you have some experience with HTML, or if you would like to learn how to make your own interactive elements, this notebook is for you! We'll cover the basics of using `@bind` with HTML elements. Let's get started!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc„§cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc¤code§y = x^2¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac„§cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac¤codeÚvmd"""
## Behind the scenes
If you're curious to learn a bit more about how this all works, keep reading!
### The output value
As we've mentioned, bound values are just the latest value of the input element, rather than some kind of observable.
The update mechanism is _lossy_ and _lazy_, which means that it will skip values if your code is still running - and **only send the latest value when your code is ready again**. This is important when changing a slider from `0` to `100`, for example. If it would send all intermediate values, it might take a while for your code to process everything, causing a noticeable lag.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$de1b9643-66fa-4918-9a93-0f340c8548ba„§cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba¤codeÙ”md"""
Now we can use the script to handle whatever interaction we want. For a simple element, let's add a button and count the number of clicks.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$82c7b1ea-08c0-495f-baba-37e5497abde2„§cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2¤codeÙ!md"""
It's as simple as that!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$cb65a4ee-02e5-4779-8728-b994d8af645d„§cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d¤code©typeof(x)¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013„§cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013¤codeÚø@bind limited_counter HTML("""
Click me!
""")¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d„§cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d¤codeÙ!@bind e html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$ced18648-7eb2-11ea-2052-07795685f0da„§cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da¤codeÚamd"#### JavaScript?
Yes! We are using `Generator.input` from [`observablehq/stdlib`](https://github.com/observablehq/stdlib#Generators_input) to create a JS _Generator_ (kind of like an Observable) that listens to `onchange`, `onclick` or `oninput` events, [depending on the element type](https://github.com/observablehq/stdlib#Generators_input).
This makes it super easy to create nice HTML/JS-based interaction elements - a package creator simply has to write a `show` method for MIME type `text/html` that creates a DOM object that triggers the `input` event. In other words, _Pluto's `@bind` will behave exactly like [`viewof` in observablehq](https://observablehq.com/@observablehq/introduction-to-views)_.
_If you want to learn more about using Javascript in Pluto, check out the [JavaScript sample notebook](https://featured.plutojl.org/web/javascript)!_"¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d„§cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d¤codeÙwmd"""
Keep in mind that changing the value of `limit` will re-evaluate the slider cell, so it will reset the value.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$bd24d02c-7eac-11ea-14ab-95021678e71e„§cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e¤codeÙ @bind x html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$0a7018ca-2afe-42b1-850f-a649e570709f„§cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f¤codeÙfmd"""
A neat aspect of this `@bind` macro is that on the Julia side, `x` is just a normal integer:
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955„§cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955¤codeÙ¯md"""
## Input types
You can use binds with anything that fires an [`input` event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event). For example:
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a„§cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a¤code¿@bind f html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51„§cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51¤codeÚ6md"""
!!! tip
Interpolating values in Javascript is neat, but remember that we are just taking the string representation of the variable and pasting it in the javascript code. For some complex data types like dates, you will need to do a bit of conversion to turn them into proper javascript expressions.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd„§cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd¤codeÚtmd"""
## Using Julia values in HTML
We've seen how you can pass on values from an interactive HTML element on to Julia, but for proper interaction, we also want to do it the other way around!
The most basic way to do this is string interpolation. In this example, you can change the value of `limit` in the code to affect the maximum value of the slider. Try it out!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122„§cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122¤code±@bind x2 myslider¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881„§cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881¤code§counter¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$e3eb31ae-c512-426f-915c-01144edbc90d„§cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d¤codeÚ¹@bind counter html"""
Click me!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2cefd0de-db13-49c1-abeb-097792ef46f6„§cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6¤codeÙŸmd"""
For something even fancier, you can also interpolate value in Javascript. For example, here I have adapted my counter so it won't count past `limit`:
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$3297233b-9567-4d5e-8138-93ebe20fed48„§cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48¤code¦x1, x2¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$cb1fd532-7eac-11ea-307c-ab16b1977819„§cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819¤code¡x¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$9985a640-c1d3-48dc-b00b-d7500085a37b„§cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b¤codeÙo@bind d html"""
First
Second
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$816ea402-7eae-11ea-2134-fb595cca3068„§cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068¤codeÙæmd"""
Not an observable, callback, or something else that you need to wrap your head around. You can use `x` like you would any other number, and Pluto's reactivity means anything depending on `x` will be updated with it. 🚀
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2„§cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¤codeÙ$@bind c html" "¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf„§cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf¤codeÙYmd"""
Okay, now we can use this HTML snippet with a `@bind` macro and see the result!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$1a338f77-d8f3-4569-a2d5-c174368a4761„§cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761¤codeÙH@bind limited HTML("""
""")¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd„§cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd¤code±@bind x1 myslider¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b„§cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b¤codeÚ+md"""
This is is how the `PlutoUI` package works - it defines HTML literals - sometimes with their own scripts.
If you've written some cool HTML inputs and you want to share them with others, you can also make a UI package! Just publish those definitions as a Julia package and you're done! ✨
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa„§cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa¤codeÙ»md"""
## Reusing elements
Once you've written some neat interactive element, you may want to use it a few times in notebook. The easiest way is to put the HTML literal in a variable.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f„§cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f¤codeÚ�md"""### What does the macro do?
The `@bind` macro does not actually contain the interactivity mechanism, this is built into Pluto itself. Still, it does two things: it assigns a _default value_ to the variable (`missing` in most cases), and it wraps the second argument in a `PlutoRunner.Bond` object.
For example, _expanding_ the `@bind` macro turns this expression:
```julia
@bind x Slider(5:15)
```
into (simplified):
```julia
begin
local el = Slider(5:15)
global x = AbstractPlutoDingetjes.intial_value(el)
PlutoRunner.create_bond(el, :x)
end
```
We see that the macro creates a variable `x`, which is given the value `AbstractPlutoDingetjes.intial_value(el)`. This function returns `missing` by default, unless a method was implemented for your widget type. For example, `PlutoUI` has a `Slider` type, and it defines a method for `intial_value(slider::Slider)` that returns the default number.
Declaring a default value using `AbstractPlutoDingetjes` is **not necessary**, as shown by the earlier examples in this notebook, but the default value will be used for `x` if the `notebook.jl` file is _run as a plain julia file_, without Pluto's interactivity.
You don't need to worry about this if you are just getting started with Pluto and interactive elements, but more advanced users should take a look at [`AbstractPlutoDingetjes.jl`](https://github.com/JuliaPluto/AbstractPlutoDingetjes.jl).
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf„§cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf¤code²(a, b, c, d, e, f)¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403„§cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403¤codeÚ‹md"""
## Scripting inputs with Javascript
You can also use Javascript to write more complicated inputs.
To get started with this, add a `
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2d8661f1-6f78-4161-a306-982e3ddf3646„§cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646¤codeÙTmyslider = html""" """;¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$db24490e-7eac-11ea-094e-9d3fc8f22784„§cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784¤codeÙðmd"""
## Bound variables
A basic interactive cell looks like this: we use the `@bind` macro, define a Julia variable, and add a bit of HTML code that creates an ` ` element. The HTML element will be rendered as the cell's output.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$901c2b84-14b8-4deb-89d6-705a4972582c„§cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c¤code¯limited_counter¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2714a923-2be5-4cf9-97dd-75347968dfee„§cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee¤code©limit = 5¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$863c5996-9892-4bfc-96ba-225fa4a2266c„§cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c¤codeÙêmd"""
!!! tip
To avoid confusing your readers, it's a good idea to put a `;` at the end of the cell where you define the interactive element, like we did here. This way, we only show sliders that are actually bound to something.
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedënotebook_idÙ$c3bafdee-b8ac-11f1-a96d-ff72b023af58«in_temp_dir¨metadata�«frontmatterˆ«license_urlÙghttps://github.com/JuliaPluto/featured/blob/2a6a9664e5428b37abe4957c1dca0994f4a8b7fd/LICENSES/Unlicense¦author‘‚¤name¨Pluto.jl£url½https://github.com/JuliaPluto¥imageÙdhttps://user-images.githubusercontent.com/6933510/174067982-904951c4-4bba-42c7-a340-102ceb7e8e10.png¥order¡1¥title·Interactivity with HTML¤tags“interactivity§classic£web§license©Unlicense«descriptionÙ.Write your own interactive controls with HTML!